/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */
package org.apache.myfaces.test.webapp.impl;

import org.apache.myfaces.test.webapp.api.ResourceFinder;
import org.apache.myfaces.test.webapp.api.annotation.*;
import org.apache.myfaces.test.webapp.api.dependencies.WebappConfiguration;
import org.apache.myfaces.test.webapp.impl.dependencies.HtmlUnitDependency;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.ByteArrayAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.jboss.shrinkwrap.api.spec.WebArchive;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * This is the manager class for creating, adding and editing archives
 * required for the test case to run. A WebArchive is created and then
 * deployed on the server using ShrinkWrap.
 *
 * @author Cosmin Martinconi, 03.07.2010
 */
public class ArchiveManager {

    private static final String LOCAL_MAVEN_REPO = System.getProperty("user.home") + File.separatorChar +
                                                   ".m2" + File.separatorChar + "repository";

    private WebArchive testArchive;
    private List<Class> suiteConfigClasses;


    public void createArchive(Archive<?> applicationArchive, String archiveName) {

        WebArchive finalArchive;
        String warArchiveName = archiveName + ".war";

        if (WebArchive.class.isInstance(applicationArchive)) {
            throw new IllegalArgumentException(WebArchive.class.getName() + " type of "
                    + applicationArchive.getName() + " instance is not allowed.");
        } else if (JavaArchive.class.isInstance(applicationArchive)) {
            finalArchive = ShrinkWrap.create(WebArchive.class, warArchiveName);
            finalArchive.addLibrary(applicationArchive);
        } else {
            finalArchive = ShrinkWrap.create(WebArchive.class, warArchiveName);
        }

        // TODO EnterpriseArchive support
        /*if (EnterpriseArchive.class.isInstance(applicationArchive)) {
            return handleArchive(EnterpriseArchive.class.cast(applicationArchive));
        }*/

        finalArchive = addDefaultDependencies(finalArchive);
        finalArchive = addHtmlUnitDependencies(finalArchive);
        finalArchive = addAnnotatedDependencies(finalArchive);

        this.testArchive = finalArchive;
    }

    public void initializeTestSuiteArchive() {
        suiteConfigClasses = new ArrayList<Class>();

        for (ConfigurationTestSuite cts : AnnotationManager.getCurrentInstance().getConfTestSuite()) {
            if (cts.configName().equals("all")) {
                suiteConfigClasses.addAll(Arrays.asList(cts.value()));
                break;
            }
        }
    }

    public static ArchiveManager getCurrentInstance() {
        return (ArchiveManager) ResourceFinder.getResource(ArchiveManager.class.getName());
    }

    private WebArchive addDefaultDependencies(WebArchive archive) {
        archive.addPackages(true,
                View.class.getPackage(),
                WebappConfiguration.class.getPackage(),
                Package.getPackage("org.apache.myfaces.test.webapp.impl"));

        return archive;
    }

    private WebArchive addHtmlUnitDependencies(WebArchive archive) {
        File[] htmlUnitArtifacts = resolveConfigurationArtifacts(HtmlUnitDependency.class);
        archive.addLibraries(htmlUnitArtifacts);
                
        return archive;
    }

    private WebArchive addAnnotatedDependencies(WebArchive archive) {

        AnnotationManager annotationManager = AnnotationManager.getCurrentInstance();

        Configuration c = annotationManager.getConfigurations();
        if (c != null) {
            archive.addLibraries(resolveConfigurationArtifacts(c.value()));
        }

        if (annotationManager.getView().id() != null)
            archive.addResource(annotationManager.getView().id());
        if (annotationManager.getView().pageBeans() != null)
            for (PageBean pb : annotationManager.getView().pageBeans())
                archive.addClass(pb.clazz());

        if (annotationManager.getView() != null) {
            archive.setWebXML("WEB-INF/web.xml");
            archive.setManifest("META-INF/MANIFEST.MF");
            archive.addWebResource("WEB-INF/faces-config.xml", "faces-config.xml");

            archive.addWebResource(new ByteArrayAsset(new byte[0]), "beans.xml");
        }

        return archive;
    }

    private File[] resolveConfigurationArtifacts(Class<? extends WebappConfiguration> configClass) {

        List<File> artifactFiles = new ArrayList<File>();

        for (WebappConfiguration w : configClass.getEnumConstants()) {

            artifactFiles.add(new File(LOCAL_MAVEN_REPO + File.separatorChar +
                    w.getGroupId().replace(".", File.separator) + File.separatorChar +
                    w.getArtifactId() + File.separatorChar +
                    w.getVersion() + File.separatorChar +
                    w.getArtifactId() + "-" + w.getVersion() + ".jar"));
        }

        return artifactFiles.toArray(new File[artifactFiles.size()]);
    }

    public WebArchive getTestSuiteArchive() {
        WebArchive suiteConfArchive = getTestArchive();
        File[] firstSuiteArtifacts = resolveConfigurationArtifacts(suiteConfigClasses.get(0));
        
        suiteConfArchive.addLibraries(firstSuiteArtifacts);
        suiteConfigClasses.remove(0);

        return suiteConfArchive;
    }

    public WebArchive getTestArchive() {
        return testArchive;
    }

    public boolean isTestSuiteConfig() {
        return suiteConfigClasses.size() != 0;
    }

}
